/*******************************************************************************
 * Copyleft (c) 2021 Kcode
 *
 * @file    yuv2rgb.c
 * @brief   转换视频数据格式，把摄像头原始的yuv格式转换成rgb565或32格式
 * @author  K
 * @version 0.0.1
 * @date    2021-07-26
 * @license MulanPSL-1.0
 *
 * 文件修改历史：
 * <时间>       | <版本>    | <作者>  | <描述>
 * 2021-07-27   | v0.0.1    | Kcode   | 转换视频数据格式
 * -----------------------------------------------------------------------------
 ******************************************************************************/

#include <linux/videodev2.h>
#include <stdlib.h>

#include "color.h"
#include "debug_manager.h"
#include "convert_manager.h"

/*!
 * @brief  判断输入输出格式是否为yuv和rgb
 * @return  0：不支持 1：支持
 */
static int isSupportYuv2Rgb(int pixel_format_in, int pixel_format_out)
{
    if (pixel_format_in != V4L2_PIX_FMT_YUYV)
        return 0;
    if ((pixel_format_out != V4L2_PIX_FMT_RGB565) && \
        (pixel_format_out != V4L2_PIX_FMT_RGB32))
        return 0;

    return 1;
}

/*!
 * @brief  支持的格式转换yuv为输出格式rgb565
 *         参考luvcview
 * @return  0：成功
 */
static unsigned int
Pyuv422torgb565(unsigned char * input_ptr, unsigned char * output_ptr, 
                unsigned int image_width, unsigned int image_height)
{
	unsigned int i, size;
	unsigned char Y, Y1, U, V;
	unsigned char *buff = input_ptr;
	unsigned char *output_pt = output_ptr;

    unsigned int r, g, b;
    unsigned int color;
    
	size = image_width * image_height /2;
	for (i = size; i > 0; i--) {
		/* bgr instead rgb ?? */
		Y = buff[0] ;
		U = buff[1] ;
		Y1 = buff[2];
		V = buff[3];
		buff += 4;
		r = R_FROMYV(Y,V);
		g = G_FROMYUV(Y,U,V); //b
		b = B_FROMYU(Y,U); //v

        /*!
         * 第一个颜色，把r,g,b三色构造为rgb565的16位值
         */
        r = r >> 3;
        g = g >> 2;
        b = b >> 3;
        color = (r << 11) | (g << 5) | b;
        *output_pt++ = color & 0xff;
        *output_pt++ = (color >> 8) & 0xff;
			
		r = R_FROMYV(Y1,V);
		g = G_FROMYUV(Y1,U,V); //b
		b = B_FROMYU(Y1,U); //v
		
        /*!
         * 第二个颜色，把r,g,b三色构造为rgb565的16位值
         */
        r = r >> 3;
        g = g >> 2;
        b = b >> 3;
        color = (r << 11) | (g << 5) | b;
        *output_pt++ = color & 0xff;
        *output_pt++ = (color >> 8) & 0xff;
	}
	
	return 0;
} 

/*!
 * @brief  支持的格式转换yuv为输出格式rgb32
 *         参考luvcview
 * @return  0：成功
 */
static unsigned int
Pyuv422torgb32(unsigned char * input_ptr, unsigned char * output_ptr, 
                    unsigned int image_width, unsigned int image_height)
{
	unsigned int i, size;
	unsigned char Y, Y1, U, V;
	unsigned char *buff = input_ptr;
	unsigned int *output_pt = (unsigned int *)output_ptr;

    unsigned int r, g, b;
    unsigned int color;

	size = image_width * image_height /2;
	for (i = size; i > 0; i--) {
		/* bgr instead rgb ?? */
		Y = buff[0] ;
		U = buff[1] ;
		Y1 = buff[2];
		V = buff[3];
		buff += 4;

        /*!
         * 第一个颜色，把r,g,b三色构造为rgb888的32位值
         */
        r = R_FROMYV(Y,V);
		g = G_FROMYUV(Y,U,V); //b
		b = B_FROMYU(Y,U); //v
		color = (r << 16) | (g << 8) | b;
        *output_pt++ = color;

        /*!
         * 第二个颜色，把r,g,b三色构造为rgb888的32位值
         */
		r = R_FROMYV(Y1,V);
		g = G_FROMYUV(Y1,U,V); //b
		b = B_FROMYU(Y1,U); //v
		color = (r << 16) | (g << 8) | b;
        *output_pt++ = color;
	}
	
	return 0;
} 

/*!
 * @brief  支持的格式转换yuv为输出格式rgb
 *         参考luvcview
 * @return  0：转换成功 -1：分配内存失败
 */
static int Yuv2RgbConvert(PT_VIDEOBUF videobuf_in,
                                    PT_VIDEOBUF videobuf_out)
{
    PT_PIXELDATAS pixeldatas_in   = &videobuf_in->pixel_data;
    PT_PIXELDATAS pixeldatas_out = &videobuf_out->pixel_data;

    pixeldatas_out->width  = pixeldatas_in->width;
    pixeldatas_out->height = pixeldatas_in->height;

    /*!
     * 判断支持哪种输出格式，调用对应的转换函数
     */
    if (videobuf_out->pixel_format == V4L2_PIX_FMT_RGB565)
    {
        pixeldatas_out->bpp = 16;
        pixeldatas_out->linebytes = pixeldatas_out->width * pixeldatas_out->bpp / 8;
        pixeldatas_out->TotalBytes = pixeldatas_out->linebytes * pixeldatas_out->height;

        if (!pixeldatas_out->PixelDatas)
        {
            pixeldatas_out->PixelDatas = (unsigned char *)malloc(pixeldatas_out->TotalBytes);
            if (!pixeldatas_out->PixelDatas)
            {
                DebugPrint(APP_ERR"pixeldatas_out->PixelDatas malloc err\n");
                return -1;
            }
        }    
        
        Pyuv422torgb565(pixeldatas_in->PixelDatas, pixeldatas_out->PixelDatas,
            pixeldatas_out->width, pixeldatas_out->height);
    }
    else if (videobuf_out->pixel_format == V4L2_PIX_FMT_RGB32)
    { 
        pixeldatas_out->bpp = 32;
        pixeldatas_out->linebytes = pixeldatas_out->width * pixeldatas_out->bpp / 8;
        pixeldatas_out->TotalBytes = pixeldatas_out->linebytes * pixeldatas_out->height;

        if (!pixeldatas_out->PixelDatas)
        {
            pixeldatas_out->PixelDatas = (unsigned char *)malloc(pixeldatas_out->TotalBytes);
            if (!pixeldatas_out->PixelDatas)
            {
                DebugPrint(APP_ERR"pixeldatas_out->PixelDatas malloc err\n");
                return -1;
            }
        }  
        
        Pyuv422torgb32(pixeldatas_in->PixelDatas, pixeldatas_out->PixelDatas,
            pixeldatas_out->width, pixeldatas_out->height);        
    }
    
    return 0;
}

/*!
 * @brief  退出函数，释放内存
 * @return  0
 */
static int Yuv2RgbConvertExit(PT_VIDEOBUF videobuf_out)
{
    if (videobuf_out->pixel_data.PixelDatas)
    {
        free(videobuf_out->pixel_data.PixelDatas);
        videobuf_out->pixel_data.PixelDatas = NULL;
    }
   
    return 0;
}

static T_VIDEOCONVERTOPR s_Yuv2RgbConvert = {
    .name        = "yuv2rgb",
    .isSupport   = isSupportYuv2Rgb,
    .Convert     = Yuv2RgbConvert,
    .ConvertExit = Yuv2RgbConvertExit,
};

extern void initLut(void);

/*!
 * @brief  初始化函数，把对支持的各个转换格式进行初始化工作
 *         对应的结构体放入链表统一管理
 * @return  0：初始化成功 1：失败
 */
int Yuv2RgbInit(void)
{
    initLut();
    return RegisterVideoConvertOpr(&s_Yuv2RgbConvert);
}

